/* global describe: false, it: false */

var should = require("should");

module.exports = function() {
    describe("定义模块", function() {
        it("定义模块，返回 Module 对象", function() {
            var m = jNs("module").define("aModule");
            m.constructor.name.should.equal("Module");
        });

        it("重复定义模块会抛出异常", function() {
            (function() {
                jNs("module").define("aModule");
            }).should.throw("[jNs] module [aModule] in namespace [module] is already defined.");
        });

        it("定义直接量模块", function() {
            var m = jNs("module").define("plainObject", {
                name: "plain"
            });
            m.exported.should.not.ok;
            m.use().should.eql({
                name: "plain"
            });
        });

        it("定义 factory 形式的模块", function() {
            var m = jNs("module").define("factoryObject", function() {
                return {
                    name: "factory"
                };
            });
            m.exported.should.not.ok;
            m.use().should.eql({
                name: "factory"
            });
        });

        it("在 factory 中引用模块对象", function() {
            var module = jNs("module").define("factoryReferece", function(m) {
                m.should.equal(module);
                m.exported.should.not.ok;
                return "reference";
            });

            module.use().should.equal("reference");
        });

        it("在 facotry 中的 this 指向模块对象", function() {
            var m = jNs("module").define("factoryThis", function() {
                this.should.equal(m);
            });
        });

        it("定义的模块的基本属性", function() {
            var m = jNs("module").define("moduleProps");
            m.name.should.equal("moduleProps");
            m.ns.should.equal(m.namespace, "Module.prototype.ns 是 Module.prototype.namespace 的别名");
            m.ns.constructor.name.should.equal("Namespace");
            m.ns.should.equal(jNs("module"));
        });

        it("使用 fullname 定义模块", function() {
            var m = jNs.define("module.fullname");
            m.name.should.equal("fullname");
            m.ns.should.equal(jNs("module"));
        });
    });

    describe("使用模块", function() {
        it("使用未定义模块会抛出异常", function() {
            (function() {
                jNs("module").use("notDefined");
            }).should.throw("[jNs] module [notDefined] in namespace [module] is not defined.");
        });

        it("使用直接量输出的模块", function() {
            jNs("module.use", function(define) {
                define("plainString", "aPlainStringModule");
                define("plainObject", {
                    name: "aPlainObjectModule"
                });
            });

            jNs("module.use").use("plainString").should.equal("aPlainStringModule");
            jNs("module.use").use("plainObject").should.eql({
                name: "aPlainObjectModule"
            });
        });

        it("使用 factory 输出的模块", function() {
            jNs("module.use", function(define) {
                define("factoryModule", function() {
                    return {
                        name: "factoryModule",
                        more: "moreInfo"
                    };
                });
            });

            jNs("module.use").use("factoryModule").should.eql({
                name: "factoryModule",
                more: "moreInfo"
            });
        });

        it("通过 fullname 使用一个模块", function() {
            var exports = {
                name: "fullname",
                ns: "module.use"
            };

            jNs("module.use").define("fullname", exports);
            jNs.use("module.use.fullname").should.equal(exports);
        });

        it("factory 函数只会执行一次", function() {
            jNs("module.use", function(define, use) {
                var count = 0;
                var m = define("factory2", function() {
                    count++;
                    return count;
                });

                use("factory2").should.equal(1);
                use("factory2").should.equal(1);
                m.use().should.equal(1);
                m.use().should.equal(1);
            });
        });
    });

    describe("类似 C# 的命名空间申明方式：jNs(name, block)", function() {
        it("可以同时申明多个模块", function() {
            var ns = jNs("nsBlock", function(define, use) {
                define("module1", "module1");
                define("module2", {
                    name: "module2"
                });
            });

            ns.name.should.equal("nsBlock");
            ns.modules.should.containDeep(["module1", "module2"]);
        });

        it("可以定义另一个同名命名空间块，合并模块定义", function() {
            var ns = jNs("nsBlock", function(define, use) {
                define("module3", function() {
                    return {
                        name: "module3"
                    };
                });

                (function() {
                    define("module1");
                }).should.throw("[jNs] module [module1] in namespace [nsBlock] is already defined.");
            });

            ns.name.should.equal("nsBlock");
            ns.modules.should.containDeep(["module1", "module2", "module3"]);
        });

        it("定义块中的 this 指向命名空间", function() {
            jNs("nsBlock", function(define, use) {
                this.should.equal(jNs("nsBlock"));
            });
        });

        it("定义块中使用其它模块", function() {
            jNs("nsBlock", function(define, use) {
                use("module1").should.equal("module1");
                use("module2").should.eql({
                    name: "module2"
                });
                use("module3").should.eql({
                    name: "module3"
                })

                define("module4", function() {
                    return {
                        name: "module4",
                        index: 3
                    };
                });

                use("module4").should.eql({
                    name: "module4",
                    index: 3
                });
            });
        });
    });
};
